package infoimport

import (
	"errors"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/config"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/dao"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/entity"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/global"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/file"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/model"
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"gopkg.in/gomail.v2"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var ExportFileLock sync.RWMutex

//导出
func ExportExcelByMail(c *gin.Context) {
	global.Log.Info("ExportExcelByMail() start.")
	//验证请求者身份
	requester := c.MustGet("USER").(*entity.Employee) //请求人
	if requester.Role != entity.EEmployeeRole_Hr {
		global.Log.Error("ImportExcel auth only for hr.", zap.Any("requester", requester))
		c.JSON(http.StatusOK, model.Fail("只有HR管理员才能导出信息"))
		return
	}

	//读取检索参数
	receiverMail := strings.TrimSpace(c.DefaultPostForm("mail", ""))
	if len(receiverMail) <= 0 {
		c.JSON(http.StatusOK, model.Fail("导出邮件接收者为空"))
		return
	}

	//指定部门，单选，若有部门只能支持1个
	var deptIdList []int64
	deptIdsStr := c.DefaultPostForm("deptId", "") //人员列表
	if deptIdsStr != "" {
		idList := strings.Split(deptIdsStr, ",")
		for _, idstr := range idList {
			id, err := strconv.ParseInt(idstr, 10, 64)
			if err == nil {
				deptIdList = append(deptIdList, id)
			}
		}
	}

	startDate := c.DefaultPostForm("startDate", "")
	endDate := c.DefaultPostForm("endDate", "")

	if len(startDate) > 0 {
		if strings.Contains(startDate, "-") { //yyyy-mm-dd格式，调整为yyyymmdd
			startDate = strings.Replace(startDate, "-", "", -1)
		}
		if strings.Contains(startDate, "/") { //yyyy/mm/dd格式，调整为yyyymmdd
			startDate = strings.Replace(startDate, "/", "", -1)
		}
		d, err := time.Parse("20060102", startDate)
		if err == nil { //日期非法
			startDate = d.Format("2006-01-02 15:04:05")
		} else {
			global.Log.Error("ImportExcel startDate format error.", zap.Any("startDate", err))
			c.JSON(http.StatusOK, model.Fail("开始日期格式错误"))
			return
		}
	}

	if len(endDate) > 0 {
		if strings.Contains(endDate, "-") { //yyyy-mm-dd格式，调整为yyyymmdd
			endDate = strings.Replace(endDate, "-", "", -1)
		}
		if strings.Contains(endDate, "/") { //yyyy/mm/dd格式，调整为yyyymmdd
			endDate = strings.Replace(endDate, "/", "", -1)
		}
		d, err := time.Parse("20060102", endDate)
		if err == nil { //日期非法
			d = d.AddDate(0, 0, 1)
			d = d.Add(-1 * time.Second)
			endDate = d.Format("2006-01-02 15:04:05")
		} else {
			global.Log.Error("ImportExcel endDate format error.", zap.Any("endDate", err))
			c.JSON(http.StatusOK, model.Fail("结束日期格式错误"))
			return
		}
	}

	status, err := strconv.Atoi(c.DefaultPostForm("status", "0"))
	if err != nil {
		status = 0 //全部
	}
	if status < entity.EVacationStatus_Draft || status > entity.EVacationStatus_Pass {
		status = 0 //全部
	}

	var applicantIdList []int64
	applicantIdsStr := c.DefaultQuery("applicantId", "") //人员列表
	if applicantIdsStr != "" {
		idList := strings.Split(applicantIdsStr, ",")
		for _, idstr := range idList {
			id, err := strconv.ParseInt(idstr, 10, 64)
			if err == nil {
				applicantIdList = append(applicantIdList, id)
			}
		}
	}

	appType, err := strconv.Atoi(c.DefaultPostForm("appType", "0")) //申请：类型1:加班、类型2：请假。 0 全部
	global.Log.Info("ExportExcelByMail param.", zap.Any("deptId", deptIdsStr),
		zap.Any("email", receiverMail),
		zap.Any("startDate", startDate),
		zap.Any("endDate", endDate),
		zap.Any("status", status),
		zap.Any("applicantId", applicantIdsStr),
		zap.Any("appType", appType))

	var applicationList []*entity.ApplicationInfo
	var applicationTotal int64
	applicationTotal = 0

	applicationTotal, applicationList, err = dao.QueryApplicationList(1, 0, entity.EDetailType_Unknow,
		status, appType, startDate, endDate, applicantIdList, deptIdList)
	if err != nil {
		global.Log.Error("ImportExcel QueryApplicationList failed.", zap.Any("error", err), zap.Any("applicationTotal", applicationTotal))
	} else {
		global.Log.Info("ImportExcel QueryApplicationList success.", zap.Any("applicationTotal", applicationTotal))
	}

	//结果导出文件
	uploadDir := config.Server().UploadDir
	_, err = os.Stat(uploadDir) //检测文件保存路径是否存在，生产上info/bin/file/opinion这个路径
	if err != nil {
		err = os.MkdirAll(uploadDir, 0777)
		if err != nil {
			global.Log.Error("Create upload dir failed.", zap.Any("err", err))
			return
		}
		global.Log.Info("Create uploadDir dir success.")
	}

	ExportFileLock.Lock()
	filename := uploadDir + "/application_" + time.Now().Format("20060102") + ".xlsx"
	if file.FileExists(filename) == true {
		err = os.Remove(filename) //文件已存在
		if err != nil {
			global.Log.Error("xlsx file has exist,and remove failed.", zap.Any("err", err))
		}
		global.Log.Info("File has exist,and remove it :", zap.Any("filename", filename))
	}
	global.Log.Info("export filename is:", zap.Any("filename", filename))
	err = exportApplicationToFile(filename, applicationList)
	ExportFileLock.Unlock()

	if err == nil {
		var emailArray []string
		emailArray = strings.Split(receiverMail, ",")
		var fileArray []string
		fileArray = append(fileArray, filename)
		err = sendGoMail(emailArray, fileArray)
		if err != nil {
			c.JSON(http.StatusOK, model.Fail("发送加班数据失败"))
			return
		} else {
			c.JSON(http.StatusOK, model.Success("发送加班数据成功"))
			return
		}
	} else {
		global.Log.Error("exportOvertimeToFile failed:", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("导出加班数据失败"))
		return
	}
	//邮件发送
}

//另存数据到文件
//return true success，and faise==failed
func exportVacationToFile(filename string, applicationArray []*entity.VacationInfo) error {
	if len(filename) <= 0 {
		return errors.New("filename is null")
	}
	xlsx := excelize.NewFile()
	xlsx.NewSheet("Sheet1") //创建sheet
	xlsx.SetActiveSheet(0)

	//title
	xlsx.SetCellStr("Sheet1", "A1", "申请人")
	xlsx.SetCellStr("Sheet1", "B1", "申请事由")
	xlsx.SetCellStr("Sheet1", "C1", "部门")
	xlsx.SetCellStr("Sheet1", "D1", "审批人")
	xlsx.SetCellStr("Sheet1", "E1", "开始日期")
	xlsx.SetCellStr("Sheet1", "F1", "结束日期")
	xlsx.SetCellStr("Sheet1", "G1", "申请日期")
	xlsx.SetCellStr("Sheet1", "H1", "申请类型")
	xlsx.SetCellStr("Sheet1", "I1", "申请状态")
	xlsx.SetCellStr("Sheet1", "J1", "备注")

	xlsx.SetColWidth("Sheet1", "A", "C", 20)
	xlsx.SetColWidth("Sheet1", "D", "D", 25)
	xlsx.SetColWidth("Sheet1", "E", "E", 40)
	xlsx.SetColWidth("Sheet1", "F", "I", 25)

	for i, app := range applicationArray {
		row := i + 2
		axisA := "A" + strconv.Itoa(row)
		axisB := "B" + strconv.Itoa(row)
		axisC := "C" + strconv.Itoa(row)
		axisD := "D" + strconv.Itoa(row)
		axisE := "E" + strconv.Itoa(row)
		axisF := "F" + strconv.Itoa(row)
		axisG := "G" + strconv.Itoa(row)
		axisH := "H" + strconv.Itoa(row)
		axisI := "I" + strconv.Itoa(row)
		axisJ := "J" + strconv.Itoa(row)

		//xlsx.SetCellInt("Sheet1", axisA, opinion.Id)
		xlsx.SetCellStr("Sheet1", axisA, app.ApplicantName) //输出到日	CreatedAt.Format("2006-01-02")
		xlsx.SetCellStr("Sheet1", axisB, app.Reason)
		xlsx.SetCellStr("Sheet1", axisC, app.DeptName)
		xlsx.SetCellStr("Sheet1", axisD, app.ApproverName)
		xlsx.SetCellStr("Sheet1", axisE, app.StartDate.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisF, app.EndDate.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisG, app.CreateAt.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisH, app.ApplyType)
		xlsx.SetCellStr("Sheet1", axisI, app.ApplyStatus)
		xlsx.SetCellStr("Sheet1", axisJ, app.Note)
	}

	err := xlsx.SaveAs(filename)
	if err != nil {
		global.Log.Error("save vacation xlsx failed.", zap.Any("error", err))
		return err
	}
	return nil
}

func exportOvertimeToFile(filename string, applicationArray []*entity.OvertimeInfo) error {
	if len(filename) <= 0 {
		return errors.New("filename is null")
	}
	xlsx := excelize.NewFile()
	xlsx.NewSheet("Sheet1") //创建sheet
	xlsx.SetActiveSheet(0)

	//title
	//xlsx.SetCellStr("Sheet1", "A1", "ID")
	xlsx.SetCellStr("Sheet1", "A1", "申请人")
	xlsx.SetCellStr("Sheet1", "B1", "申请事由")
	xlsx.SetCellStr("Sheet1", "C1", "部门")
	xlsx.SetCellStr("Sheet1", "D1", "审批人")
	xlsx.SetCellStr("Sheet1", "E1", "开始日期")
	xlsx.SetCellStr("Sheet1", "F1", "结束日期")
	xlsx.SetCellStr("Sheet1", "G1", "申请日期")
	xlsx.SetCellStr("Sheet1", "H1", "申请类型")
	xlsx.SetCellStr("Sheet1", "I1", "申请状态")
	xlsx.SetCellStr("Sheet1", "J1", "备注")

	xlsx.SetColWidth("Sheet1", "A", "C", 20)
	xlsx.SetColWidth("Sheet1", "D", "D", 25)
	xlsx.SetColWidth("Sheet1", "E", "E", 40)
	xlsx.SetColWidth("Sheet1", "F", "I", 25)

	for i, app := range applicationArray {
		row := i + 2
		axisA := "A" + strconv.Itoa(row)
		axisB := "B" + strconv.Itoa(row)
		axisC := "C" + strconv.Itoa(row)
		axisD := "D" + strconv.Itoa(row)
		axisE := "E" + strconv.Itoa(row)
		axisF := "F" + strconv.Itoa(row)
		axisG := "G" + strconv.Itoa(row)
		axisH := "H" + strconv.Itoa(row)
		axisI := "I" + strconv.Itoa(row)
		axisJ := "J" + strconv.Itoa(row)

		//xlsx.SetCellInt("Sheet1", axisA, opinion.Id)
		//xlsx.SetCellInt("Sheet1", axisA, opinion.Id)
		xlsx.SetCellStr("Sheet1", axisA, app.ApplicantName) //输出到日	CreatedAt.Format("2006-01-02")
		xlsx.SetCellStr("Sheet1", axisB, app.Reason)
		xlsx.SetCellStr("Sheet1", axisC, app.DeptName)
		xlsx.SetCellStr("Sheet1", axisD, app.ApproverName)
		xlsx.SetCellStr("Sheet1", axisE, app.StartDate.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisF, app.EndDate.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisG, app.CreateAt.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisH, app.ApplyType)
		xlsx.SetCellStr("Sheet1", axisI, app.ApplyStatus)
		xlsx.SetCellStr("Sheet1", axisJ, app.Note)
	}

	err := xlsx.SaveAs(filename)
	if err != nil {
		global.Log.Error("save overtime xlsx failed.", zap.Any("error", err))
		return err
	}
	return nil
}

func exportApplicationToFile(filename string, applicationArray []*entity.ApplicationInfo) error {
	if len(filename) <= 0 {
		return errors.New("filename is null")
	}
	xlsx := excelize.NewFile()
	xlsx.NewSheet("Sheet1") //创建sheet
	xlsx.SetActiveSheet(0)

	//title
	//xlsx.SetCellStr("Sheet1", "A1", "ID")
	xlsx.SetCellStr("Sheet1", "A1", "申请人")
	xlsx.SetCellStr("Sheet1", "B1", "申请事由")
	xlsx.SetCellStr("Sheet1", "C1", "部门")
	xlsx.SetCellStr("Sheet1", "D1", "审批人")
	xlsx.SetCellStr("Sheet1", "E1", "开始日期")
	xlsx.SetCellStr("Sheet1", "F1", "结束日期")
	xlsx.SetCellStr("Sheet1", "G1", "申请日期")
	xlsx.SetCellStr("Sheet1", "H1", "申请类型")
	xlsx.SetCellStr("Sheet1", "I1", "申请状态")
	xlsx.SetCellStr("Sheet1", "J1", "备注")

	xlsx.SetColWidth("Sheet1", "A", "C", 20)
	xlsx.SetColWidth("Sheet1", "D", "D", 25)
	xlsx.SetColWidth("Sheet1", "E", "E", 40)
	xlsx.SetColWidth("Sheet1", "F", "I", 25)

	for i, app := range applicationArray {
		row := i + 2
		axisA := "A" + strconv.Itoa(row)
		axisB := "B" + strconv.Itoa(row)
		axisC := "C" + strconv.Itoa(row)
		axisD := "D" + strconv.Itoa(row)
		axisE := "E" + strconv.Itoa(row)
		axisF := "F" + strconv.Itoa(row)
		axisG := "G" + strconv.Itoa(row)
		axisH := "H" + strconv.Itoa(row)
		axisI := "I" + strconv.Itoa(row)
		axisJ := "J" + strconv.Itoa(row)

		//xlsx.SetCellInt("Sheet1", axisA, opinion.Id)
		//xlsx.SetCellInt("Sheet1", axisA, opinion.Id)
		xlsx.SetCellStr("Sheet1", axisA, app.ApplicantName) //输出到日	CreatedAt.Format("2006-01-02")
		xlsx.SetCellStr("Sheet1", axisB, app.Reason)
		xlsx.SetCellStr("Sheet1", axisC, app.DeptName)
		xlsx.SetCellStr("Sheet1", axisD, app.ApproverName)
		xlsx.SetCellStr("Sheet1", axisE, app.StartDate.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisF, app.EndDate.Format("2006-01-02"))
		xlsx.SetCellStr("Sheet1", axisG, app.CreateAt.Format("2006-01-02"))
		if app.ApplicationType == 1 {
			xlsx.SetCellStr("Sheet1", axisH, "加班")
		} else if app.ApplicationType == 2 {
			xlsx.SetCellStr("Sheet1", axisH, "请假")
		} else {
			xlsx.SetCellStr("Sheet1", axisH, "--")
		}
		xlsx.SetCellStr("Sheet1", axisI, app.ApplyStatus)
		xlsx.SetCellStr("Sheet1", axisJ, app.Note)
	}

	err := xlsx.SaveAs(filename)
	if err != nil {
		global.Log.Error("save overtime xlsx failed.", zap.Any("error", err))
		return err
	}
	return nil
}

//目标地址
func sendGoMail(mailAddress []string, files []string) error {
	global.Log.Info("sendGoMail() start")
	if len(files) <= 0 {
		return errors.New("No find attach files.")
	}
	if len(mailAddress) <= 0 {
		return errors.New("Unspecified email address")
	}

	m := gomail.NewMessage()
	// 这种方式可以添加别名，即 nickname， 也可以直接用<code>m.SetHeader("From", MAIL_USER)</code>
	nickname := "dfitc hr"

	m.SetHeader("From", nickname+"<"+config.EMailSetting().Mailuser+">")
	// 发送给多个用户
	m.SetHeader("To", mailAddress...)
	// 设置邮件主题
	subject := "外包人员考勤数据导出" + time.Now().Format("20060102")
	m.SetHeader("Subject", subject)
	// 设置邮件正文
	body := "数据参见附件"
	m.SetBody("text/html", body)

	for _, file := range files {
		m.Attach(file)
	}

	d := gomail.NewDialer(config.EMailSetting().Mailhost, config.EMailSetting().Mailport,
		config.EMailSetting().Mailuser, config.EMailSetting().Mailpwd)

	d.SSL = true
	// 发送邮件
	err := d.DialAndSend(m)
	if err != nil {
		global.Log.Error("sendGoMail() failed,error:=", zap.Any("error", err))
	} else {
		global.Log.Info("sendGoMail() finished,success")
	}
	return err
}
